/*
silverPDF is sponsored by Aleyant Systems (http://www.aleyant.com)

silverPDF is based on PdfSharp (http://www.pdfsharp.net) and iTextSharp (http://itextsharp.sourceforge.net)

Developers: Ai_boy (aka Oleksii Okhrymenko)

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above information and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR SPONSORS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

*/
//
// PDFsharp - A library for processing PDF
//
// Authors:
//   Klaus Potzesny (mailto:Klaus.Potzesny@pdfsharp.com)
//
// Copyright (c) 2005-2008 empira Software GmbH, Cologne (Germany)
//
// http://www.pdfsharp.com
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Diagnostics;
using PdfSharp.Drawing;

namespace PdfSharp.Drawing.BarCodes
{
  /// <summary>
  /// Internal base class for several bar code types.
  /// </summary>
  public abstract class ThickThinBarCode : BarCode  // TODO: The name is not optimal
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="ThickThinBarCode"/> class.
    /// </summary>
    public ThickThinBarCode(string code, XSize size, CodeDirection direction)
      : base(code, size, direction)
    {
    }

    internal override void InitRendering(BarCodeRenderInfo info)
    {
      base.InitRendering(info);
      CalcThinBarWidth(info);
      info.BarHeight = Size.Height;
      // HACK 
      if (this.textLocation != TextLocation.None)
        info.BarHeight *= 4.0 / 5;

#if DEBUG_
      XColor back = XColors.LightSalmon;
      back.A = 0.3;
      XSolidBrush brush = new XSolidBrush(back);
      info.Gfx.DrawRectangle(brush, new XRect(info.Center - this.size / 2, this.size));
#endif
      switch (this.direction)
      {
        case CodeDirection.RightToLeft:
          info.Gfx.RotateAtTransform(180, info.Position);
          break;

        case CodeDirection.TopToBottom:
          info.Gfx.RotateAtTransform(90, info.Position);
          break;

        case CodeDirection.BottomToTop:
          info.Gfx.RotateAtTransform(-90, info.Position);
          break;
      }
    }

    /// <summary>
    /// Gets or sets the ration between thick an thin lines. Must be between 2 an 3.
    /// Optimal and also default value is 2.6.
    /// </summary>
    public override double WideNarrowRatio
    {
      get { return this.wideNarrowRatio; }
      set
      {
        if (value > 3 || value < 2)
          throw new ArgumentOutOfRangeException("value", BcgSR.Invalid2of5Relation);
        this.wideNarrowRatio = value;
      }
    }
    internal double wideNarrowRatio = 2.6;

    /// <summary>
    /// Renders a thick or thin line for the bar code.
    /// </summary>
    /// <param name="info"></param>
    /// <param name="isThick">Determines whether a thick or a thin line is about to be rendered.</param>
    internal void RenderBar(BarCodeRenderInfo info, bool isThick)
    {
      double barWidth = GetBarWidth(info, isThick);
      double height = Size.Height;
      if (TextLocation != TextLocation.None)
        height *= 4.0 / 5;
      XRect rect = new XRect(info.CurrPos.X, info.CurrPos.Y, barWidth, height);
      info.Gfx.DrawRectangle(info.Brush, rect);
      info.CurrPos.X += barWidth;
    }

    /// <summary>
    /// Renders a thick or thin gap for the bar code.
    /// </summary>
    /// <param name="info"></param>
    /// <param name="isThick">Determines whether a thick or a thin gap is about to be rendered.</param>
    internal void RenderGap(BarCodeRenderInfo info, bool isThick)
    {
      info.CurrPos.X += GetBarWidth(info, isThick);
    }

    /// <summary>
    /// Renders a thick bar before or behind the code.
    /// </summary>
    internal void RenderTurboBit(BarCodeRenderInfo info, bool startBit)
    {
      if (startBit)
        info.CurrPos.X -= 0.5 + GetBarWidth(info, true);
      else
        info.CurrPos.X += 0.5; //GetBarWidth(info, true);

      RenderBar(info, true);

      if (startBit)
        info.CurrPos.X += 0.5; //GetBarWidth(info, true);
    }

    internal void RenderText(BarCodeRenderInfo info)
    {
      if (info.Font == null)
        info.Font = new XFont("Courier New", Size.Height / 6);
      XPoint center = info.Position + CodeBase.CalcDistance(this.anchor, AnchorType.TopLeft, this.size);
      //center.Y += info.Font.Size;
      info.Gfx.DrawString(this.text, info.Font, info.Brush, new XRect(center, Size), XStringFormats.BottomCenter);
    }

    /// <summary>
    /// Gets the width of a thick or a thin line (or gap). CalcLineWidth must have been called before.
    /// </summary>
    /// <param name="info"></param>
    /// <param name="isThick">Determines whether a thick line's with shall be returned.</param>
    internal double GetBarWidth(BarCodeRenderInfo info, bool isThick)
    {
      if (isThick)
        return info.ThinBarWidth * this.wideNarrowRatio;
      else
        return info.ThinBarWidth;
    }

    internal abstract void CalcThinBarWidth(BarCodeRenderInfo info);
  }
}
